#include "DefaultSceneGraph.h"

namespace Nezha
{

	SceneNode* DefaultSceneGraph::createSceneNode(const _string& name, SceneNode* parent)
	{
		SceneNode* sn = NULL;

		if(mSceneNodes.search(name, sn))
		{
			NZError("Faild to create scene node with name %s, the name was engaged.");
			return NULL;
		}

		sn = NZ_New SceneNode(name);
		mSceneNodes.insert(name, sn);

		if(parent)
		{
			parent->attachChild(sn);
		}
		else
		{
			mRootNode->attachChild(sn);
		}

		return sn;
	}

	SceneNode* DefaultSceneGraph::findSceneNode(const _string& name)
	{
		SceneNode* sn = NULL;
		if(!mSceneNodes.search(name, sn))
		{
			NZDebug("failed to find scene node %s", name.c_str());
			sn = NULL;
		}

		return sn;
	}

	void DefaultSceneGraph::destroySceneNode(SceneNode* sn)
	{
		if(!mSceneNodes.search(sn->getName(), sn))
		{
			NZError("Invalid scene node %s, it's not contained in scene graph.");
			return;
		}

		if(!mSceneNodes.remove(sn->getName()))
		{
			NZ_ASSERT(false);
		}

		//mSceneNodeGarbages.push_back(sn);

		if(sn->getBindedObject())
		{
			sn->bindOject(NULL);
		}

		if(sn->getParentSceneNode())
		{
			sn->getParentSceneNode()->removeChild(sn);
		}

		NZ_Delete sn;
	}

	SceneObject* DefaultSceneGraph::findObject(const _string& name)
	{
		SceneObject* so = NULL;
		if(!mSceneObjects.search(name, so))
		{
			NZDebug("failed to find scene object %s", name.c_str());
			so = NULL;
		}

		return so;
	}

	SceneObject* DefaultSceneGraph::create(const _string& name, SceneObjectCreation* params, SceneNode* bindNode /* = NULL */)
	{
		if(!params)
		{
			return NULL;
		}

		SceneObject* so = NULL;

		if(mSceneObjects.search(name, so))
		{
			NZError("Object %s already exsit, failed to create.", name.c_str());
			return NULL;
		}

		SceneObjectFactory* fac = getFactoryByTypeInt(params->getObjectTypeInteger());

		if(!fac)
		{
			NZError("Unknown type of object, failed to create.");
			return NULL;
		}

		so = fac->create(name, params);
		if(bindNode)
		{
			bindNode->bindOject(so);
		}

		_insertObject(so);

		return so;
	}

	void DefaultSceneGraph::destroySceneObject(SceneObject* so)
	{
		if(!so)
		{
			return;
		}

		SceneNode* sn = so->getSceneNode();
		if(sn)
		{
			u32 num = sn->getNumChildren();
			for(u32 i = 0; i < num; i++)
			{
				SceneNode* ch_sn = sn->getChild(i);
				destroySceneObject(ch_sn->getBindedObject());
			}

			if(sn->getParentSceneNode())
			{
				sn->getParentSceneNode()->removeChild(sn);
			}

			destroySceneNode(sn);
		}


		mSceneObjects.remove(so->getName());

		// any other destruction callback?
		NZ_Delete so;
	}

	SceneObjectFactory* DefaultSceneGraph::getFactoryByTypeInt(int sot)
	{
		SceneObjFacIntMap::iterator it = mSceneFacIntMap.find(sot);

		if(it != mSceneFacIntMap.end())
		{
			return it->second;
		}

		return NULL;
	}

	void DefaultSceneGraph::setSceneObjectFactory(SceneObjectFactory* fac)
	{
		if(fac)
		{
			SceneObjFacIntMap::iterator it = mSceneFacIntMap.find(fac->getObjectTypeInteger());

			if(it != mSceneFacIntMap.end())
			{
				NZWarning("Scene object manager %s already exist.", fac->getObjectType().c_str());
				return;
			}

			mSceneFacIntMap.insert(MapPair<int, SceneObjectFactory*>(fac->getObjectTypeInteger(), fac));
		}
	}

	void DefaultSceneGraph::update(float dt)
	{
		// TODO ?
	}

	SceneObjectCreation* DefaultSceneGraph::loadScript(const _string& scriptName)
	{
		// TODO

		return NULL;
	}

	void DefaultSceneGraph::_insertObject(SceneObject* so)
	{
		mSceneObjects.insert(so->getName(), so);
	}

}//end namespace Nezha